42. 数据结构之列表

本章导览:列表——Python最核心的数据结构

列表(List)是Python中使用频率最高的数据结构:

  • 可变性:元素可直接修改,适合实时数据更新
  • 有序性:维护插入顺序,天然适合时间序列
  • 异构性:可存储任意类型对象,灵活处理混合数据
  • 动态性:自动扩容,支持增量数据采集

列表的技术原理:动态数组

列表基于动态数组(Dynamic Array)实现:

  • 连续内存存储:利用局部性原理,提高CPU缓存命中率
  • 自动扩容机制:空间不足时自动分配更大内存块
  • 几何增长策略:新容量 \(\approx\) 旧容量 \(\times 1.125 + C\)
  • 对于插入n个元素,扩容次数仅需 \(O(\log n)\)
  • 单次操作的均摊时间复杂度\(O(1)\)

列表四大特性与金融场景

特性 技术实现 时间复杂度 金融应用场景
可变性 元素直接修改 O(1) 实时价格更新
有序性 维护插入顺序 - 时间序列数据
异构性 存储任意类型 - 混合数据记录
动态性 自动扩容 amortized O(1) 增量数据采集

⭐ 平台任务解答代码

Listing 1
# 注:该代码块包含未完成的填空代码,需要在平台上完成
# 注意:此答案不全,请查阅平台。
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"]  #创建指数名称列的列表
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
print(name_index[2])        #访问 "标普500指数" 这个元素
 
print(price_index.index(8376.63))       #找出 8376.63 这个元素所在的索引值

#任务二
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
name_index.append("法国CAC40指数")         #按要求添加新元素
name_index.append("德国DAX指数")  # 将股指名称添加到列表
name_index.append("新加坡海峡指数")  # 将股指名称添加到列表
name_index.append("台湾加权指数")  # 将股指名称添加到列表
print(name_index)                   #打印添加新元素后的name_index列表
 
price_index.append(7630.95)         #按要求添加新元素
price_index.append(18906.92)  # 将股指收盘点数添加到列表
price_index.append(3442.93)  # 将股指收盘点数添加到列表
price_index.append(22268.09)  # 将股指收盘点数添加到列表
print(price_index)                 #打印添加新元素后的price_index列表


#任务三
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index                         
 
price_index.remove(38647.75)  #删除"日经225指数"这个元素
                             
 
price_index.insert(6,2674.45)  #添加索引为6的"韩国综合指数"这个元素
print(name_index)  # 输出指数数据
print(price_index)  # 输出价格数据

#任务四
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
price_index.sort()     #将price_index列表元素由小到大排序
print(price_index)  # 输出价格数据

price_index.reverse()     #将price_index列表元素翻转
print(price_index)  # 输出价格数据

price_index.clear()  #删除price_index列表全部元素(使用clear函数)
print(price_index)  # 输出价格数据

创建列表与访问元素

Listing 2
# 创建列表:存储券商股票名称
# 方括号[]是列表的字面量语法
stocks = ['中信证券', '国泰君安', '海通证券', '华泰证券']

# 访问元素:索引从0开始
print('第一个:', stocks[0])

# 负数索引:-1表示最后一个元素
print('最后一个:', stocks[-1])
第一个: 中信证券
最后一个: 华泰证券

列表的切片操作

Listing 3
stocks = ['中信证券', '国泰君安', '海通证券', '华泰证券']

# 切片操作:[start:end],包含start,不包含end
# stocks[:3]等价于stocks[0:3],获取前3个元素
print('前3个:', stocks[:3])

# stocks[1:4]获取索引1到3的元素
# 切片操作创建列表的浅拷贝,不会修改原列表
print('第2-4个:', stocks[1:4])
前3个: ['中信证券', '国泰君安', '海通证券']
第2-4个: ['国泰君安', '海通证券', '华泰证券']

修改与添加元素

Listing 4
stocks = ['中信证券', '国泰君安', '海通证券', '华泰证券']

# 修改元素:通过索引直接赋值
stocks[1] = '申万宏源'
print('修改后:', stocks)

# 添加元素:append()在列表末尾添加
# 时间复杂度为 amortized O(1),非常高效
stocks.append('招商证券')
print('追加后:', stocks)
修改后: ['中信证券', '申万宏源', '海通证券', '华泰证券']
追加后: ['中信证券', '申万宏源', '海通证券', '华泰证券', '招商证券']

删除元素

Listing 5
stocks = ['中信证券', '申万宏源', '海通证券', '华泰证券', '招商证券']

# remove()方法:删除第一个匹配的元素
# 需要先查找元素,时间复杂度为 O(n)
stocks.remove('海通证券')
print('删除后:', stocks)
删除后: ['中信证券', '申万宏源', '华泰证券', '招商证券']

常用操作的时间复杂度

操作 时间复杂度 说明
lst[i] O(1) 索引访问
lst.append(x) amortized O(1) 末尾追加
lst.insert(i, x) O(n) 任意位置插入
lst.pop() O(1) 弹出末尾
lst.pop(0) O(n) 弹出首元素
lst.remove(x) O(n) 删除指定值

排序与反转

Listing 6
numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# sorted()函数:返回排序后的新列表,原列表不变
# 使用Timsort算法,时间复杂度 O(n log n)
numbers_sorted = sorted(numbers)
print('排序:', numbers_sorted)

# reverse()方法:原地反转列表,时间复杂度 O(n)
numbers_sorted.reverse()
print('反转:', numbers_sorted)
排序: [1, 1, 2, 3, 4, 5, 6, 9]
反转: [9, 6, 5, 4, 3, 2, 1, 1]

统计与聚合操作

Listing 7
numbers_sorted = [9, 6, 5, 4, 3, 2, 1, 1]

# count():统计元素出现次数,时间复杂度 O(n)
print(f'计数(1): {numbers_sorted.count(1)}')

# sum():计算元素和,时间复杂度 O(n)
print(f'求和: {sum(numbers_sorted)}')

# len():获取列表长度,时间复杂度 O(1)
print(f'长度: {len(numbers_sorted)}')
计数(1): 2
求和: 31
长度: 8

易混淆概念:sort() vs sorted()

方法 原地修改 返回值 使用场景
list.sort() None 不需要保留原列表
sorted(list) 新列表 需要保留原顺序
Listing 8
original = [3, 1, 2]
new_list = sorted(original)  # 创建新列表
print('原列表:', original)   # [3, 1, 2] — 不变
print('新列表:', new_list)   # [1, 2, 3] — 排序后
原列表: [3, 1, 2]
新列表: [1, 2, 3]

列表推导式

Listing 9
numbers = [9, 6, 5, 4, 3, 2, 1, 1]

# 列表推导式:比传统for循环更快、更Pythonic
# 语法:[expression for item in iterable]
squares = [x**2 for x in numbers]
print('平方:', squares)
平方: [81, 36, 25, 16, 9, 4, 1, 1]

金融应用:投资组合管理

Listing 10
# 定义持仓股票组合
# 列表+字典的嵌套结构,适合表示"实体-属性"关系
portfolio = [
    {'code': '600519.SH', 'name': '贵州茅台', 'shares': 100, 'price': 1850.00},
    {'code': '000858.SZ', 'name': '五粮液', 'shares': 200, 'price': 220.50},
    {'code': '600036.SH', 'name': '招商银行', 'shares': 500, 'price': 45.20}
]

total_value = 0
for stock in portfolio:
    value = stock['shares'] * stock['price']
    total_value += value
    print(f"{stock['name']}: {value:,.2f}元")

print(f'\n总投资: {total_value:,.2f}元')
贵州茅台: 185,000.00元
五粮液: 44,100.00元
招商银行: 22,600.00元

总投资: 251,700.00元

投资组合:权重计算

Listing 11
portfolio = [
    {'code': '600519.SH', 'name': '贵州茅台', 'shares': 100, 'price': 1850.00},
    {'code': '000858.SZ', 'name': '五粮液', 'shares': 200, 'price': 220.50},
    {'code': '600036.SH', 'name': '招商银行', 'shares': 500, 'price': 45.20}
]

# 计算总价值
total_value = sum(s['shares'] * s['price'] for s in portfolio)

# 计算每只股票的权重
weights = []
for stock in portfolio:
    value = stock['shares'] * stock['price']
    weight = value / total_value
    weights.append(weight)
    print(f"{stock['name']}: {weight:.2%}")

print(f'权重总和: {sum(weights):.4f}')
贵州茅台: 73.50%
五粮液: 17.52%
招商银行: 8.98%
权重总和: 1.0000

列表的内存效率分析

对于n个元素的列表:

  • 引用数组:n × 8字节(64位系统)
  • 对象开销:每个对象约56字节(Python对象头)
  • 1000个整数的列表 ≈ 64 KB

相比之下,NumPy数组只需约 8 KB(紧凑存储)

选择合适的数据结构

需求场景 推荐数据结构 原因
频繁添加/删除 列表 动态数组
频繁头部操作 collections.deque 双端队列 O(1)
快速查找 字典/集合 哈希表 O(1)
大规模数值计算 NumPy数组 内存紧凑

性能优化技巧

  • list.append() 而非 list + [x](后者创建新列表)
  • 列表推导式代替传统for循环(字节码优化)
  • 已知大小时预分配[None] * n
  • extend() 批量添加,比循环 append() 更高效

本章总结

  • 列表是Python最常用的动态数组,支持增删改查
  • 索引从0开始,支持负数索引和切片操作
  • append() 效率最高(O(1)),insert()/remove() 为 O(n)
  • sort() vs sorted():前者原地修改,后者返回新列表
  • 列表推导式是创建新列表的Pythonic方式
  • 嵌套列表+字典可实现投资组合管理等金融应用